#pragma once

#include<iostream>
#include<pthread.h>
#include<vector>
#include<unistd.h>
#include<queue>
#include"Task.hpp"
#include<cstdio>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

using namespace std;

const int n = 5;

template<class T>

class ThreadPool
{
public:
  ThreadPool(int num = n)
    :_threads(num)
    ,_num(num)
  {
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_cond,nullptr);
  }
  
  void Lock()
  {
    pthread_mutex_lock(&_mutex);
  }

  void UnLock()
  {
    pthread_mutex_unlock(&_mutex);
  }

  void Wait()
  {
    pthread_cond_wait(&_cond, &_mutex);
  }

  void Wakeup()
  {
    pthread_cond_signal(&_cond);
  }

  void push(const T& key)
  {
    Lock();//vector没有空间限制，不怕空间不够，不用判断
    _task.push(key);
    Wakeup();//有数据了，唤醒线程去pop
    UnLock();
  }

  void pop(T& key)
  {
    Lock();
    while(_task.empty())//因为怕没有数据，所以要进行判断
    {
      Wait();
    }
    UnLock();
    key = _task.front();
    _task.pop();
  }

  static void* ThreadRoutine(void* args)//由于成员函数会有this指针的参数，导致传参出现问题，所以这里采用static
  {                                   //但是，使用了static，就无法使用成员参数，所以直接传参args，为this指针
    ThreadPool<T>* This = static_cast<ThreadPool<T> *>(args);
    pthread_detach(pthread_self());
    while(true)
    {
      T t; 
      This->pop(t);
      t();
      pthread_mutex_lock(&mutex);
      cout << "某个线程处理任务 : " << t.FormatRes()  << endl; 
      pthread_mutex_unlock(&mutex);
    }
  }

  void start()
  {
    for(auto& thread : _threads)
    {
      pthread_create(&thread,nullptr,ThreadRoutine,this);
    }
  }

  ~ThreadPool()
  { 
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
  }
private:
  vector<pthread_t> _threads;//存储线程
  int _num;//线程的数量
  queue<T> _task;//任务
  pthread_mutex_t _mutex;//互斥
  pthread_cond_t _cond;//同步
};
